package com.cxs.handler;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.cxs.constant.AuthConstant;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.Duration;
import java.util.*;

/**
 * @Author: CXS
 * 登录成功后的处理器
 * 登录还是走security的
 * 登录成功后 我们拿到用户信息 然后转成jwt 返回给前段
 */
@Configuration
public class JwtLoginSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 登录成功后执行的处理方法
     *
     * @param request
     * @param response
     * @param authentication
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        String jwtToken = null;
        // 拿到用户的名字
        String userName = ((User) (authentication.getPrincipal())).getUsername();
        // 拿到权限
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        List<String> auths = new ArrayList<>(authorities.size() * 2);
        // 放到自己的list里面去
        authorities.forEach(authority -> auths.add(authority.getAuthority()));
        // 设置颁发时间
        Date createTime = new Date();
        // 设置过期时间 我们可以设置2小时
        Calendar now = Calendar.getInstance();
        now.set(Calendar.SECOND, 7200);
        // 得到过期时间
        Date expireTime = now.getTime();
        // 生产token
        jwtToken = JWT.create()
                .withSubject(userName) // 名字
                .withClaim("auths",auths) // 权限
                .withIssuedAt(createTime)
                .withExpiresAt(expireTime)
                .sign(Algorithm.HMAC256(AuthConstant.AUTH_JWT_KEY_SIGN));
        // 记得把token放在redis里面做登出 因为jwt和服务器是无状态的 一旦颁发有效期内都可以访问
        // 如果用户修改了密码等信息 需要结合业务做登出
        redisTemplate.opsForValue().set(AuthConstant.AUTH_JWT_PREFIX + jwtToken, "", Duration.ofSeconds(7200));
        // 把token写出去
        HashMap<String, Object> data = new HashMap<>(8);
        data.put("code", 200);
        data.put("access_token", jwtToken);
        data.put("type", "bearer");
        data.put("expires_in", 7200);
        // 设置响应头
        response.addHeader("content-type", "application/json;charset=utf-8");
        // 转成字符串
        ObjectMapper objectMapper = new ObjectMapper();
        String result = objectMapper.writeValueAsString(data);
        // 写出去
        PrintWriter writer = response.getWriter();
        writer.write(result);
        writer.flush();
        writer.close();
    }
}
